package com.ifast.integral.service.impl;

import java.util.Calendar;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.ifast.common.utils.Const;
import com.ifast.common.utils.Const.integral;
import com.ifast.integral.dao.IntegralUserDao;
import com.ifast.integral.domain.IntegralConfig;
import com.ifast.integral.domain.IntegralHistory;
import com.ifast.integral.domain.IntegralTimeRecord;
import com.ifast.integral.domain.IntegralUser;
import com.ifast.integral.service.IntegralConfigService;
import com.ifast.integral.service.IntegralFromService;
import com.ifast.integral.service.IntegralHistoryService;
import com.ifast.integral.service.IntegralTimeRecordService;
import com.ifast.sys.service.UserService;
import com.luculent.util.extension.api.Result;

import cn.hutool.core.collection.CollectionUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

/**
 * 
 * @author ShiQiang
 * @date 2019年4月9日09:56:53
 */
@Transactional
@Service("integralFromService")
public class IntegralFromServiceImpl extends ServiceImpl<IntegralUserDao, IntegralUser> implements IntegralFromService{
	
	@Autowired
    private IntegralConfigService integralConfigService;
	@Autowired
	private IntegralHistoryService integralHistoryService;
	@Autowired
	private IntegralTimeRecordService integralTimeRecordService;
	 
	@Autowired
	private UserService userService;
	
	
	@Override
	public void obtainAspectIntegral(String userId, String dwCode, integral integral) {
		Open config = getConfig(dwCode);
		//1积分未开启
		if(config.isOpen) 
			return ;
		//最大上限
		Calendar calendar = Calendar.getInstance(); 
		List<IntegralHistory> histories = getHistory(calendar, userId, integral);
		InConfig conf = getMinMax(integral,config.getConfig());
		
		int addScore = 0;
		if(CollectionUtil.isEmpty(histories)){ 
			//今天没有记录
			addScore = conf.getMin();  
		}else{
			addScore = addScore(histories,conf,false); 
		}
		
		if(addScore <= 0)
			return ;
		updateUserScore(userId,dwCode,addScore);
		//添加历史记录
		saveHistory(conf,userId,dwCode,null,addScore,calendar);
	} 
	
	@Override
	public void obtainIntegral(String userId, String dwCode, integral integral, String businessId, boolean right) {
		Open config = getConfig(dwCode);
		//1积分未开启
		if(config.isOpen){
			statistics(integral.getValue(),userId,0);
			return ;
		}
		//2重复记录不得分-不分时间
		if(integralHistoryService.selectCount(new EntityWrapper<IntegralHistory>().eq("BUSINESS_ID", businessId).eq("USER_ID", userId)) > 0 ){
			statistics(integral.getValue(),userId,0);
			return ;
		}
		//最大上限
		Calendar calendar = Calendar.getInstance(); 
		List<IntegralHistory> histories = getHistory(calendar, userId, integral);
		InConfig conf = getMinMax(integral,config.getConfig());
		
		int addScore = 0;
		if(CollectionUtil.isEmpty(histories)){ 
			//今天没有记录
			addScore = right ? conf.getLongAndRight() : conf.getMin(); 
		}else{
			addScore = addScore(histories,conf,right);
		}
		
		if(addScore <= 0){
			statistics(integral.getValue(),userId,0);
			return ;
		}
		
		updateUserScore(userId,dwCode,addScore);
		saveHistory(conf,userId,dwCode,businessId,addScore,calendar);
		
	}
	
	@Override
	public void obtainIntegral(String userId, String dwCode, integral integral, String businessId) {
		Open config = getConfig(dwCode);
		//1积分未开启
		if(config.isOpen) 
			return ;
		//2重复记录不得分 - 不分时间
		if(integralHistoryService.selectCount(new EntityWrapper<IntegralHistory>().eq("BUSINESS_ID", businessId).eq("USER_ID", userId)) > 0 )
			return ;
		
		Calendar calendar = Calendar.getInstance(); 
		InConfig conf = getMinMax(integral,config.getConfig());
		//是否达到时长进行积分
		if(timeLongAllow(userId,businessId,conf,calendar))
			return ;
		//积分最大上限
		List<IntegralHistory> histories = getHistory(calendar, userId, integral); 
		int addScore = 0;
		if(CollectionUtil.isEmpty(histories)){ 
			//今天没有记录
			addScore = conf.getMin(); 
		}else{
			addScore = addScore(histories,conf,false);
		}
		
		if(addScore <= 0)
			return ;
		
		updateUserScore(userId,dwCode,addScore);
		saveHistory(conf,userId,dwCode,businessId,addScore,calendar); 
	} 
	
	private boolean timeLongAllow(String userId,String businessId,InConfig conf,Calendar calendar){ 
		IntegralTimeRecord timeRecord = integralTimeRecordService.selectOne(new EntityWrapper<IntegralTimeRecord>(IntegralTimeRecord.builder().userId(userId).businessId(businessId).build()));
		if(timeRecord == null || timeRecord.getTimeLong() == null || conf.getLongAndRight() <= 0)
			return true; 
		if(conf.getLongAndRight() > (calendar.getTimeInMillis() - timeRecord.getTimeLong()))
			return true;
		//删除记录防止重复判断
		integralTimeRecordService.delete(new EntityWrapper<IntegralTimeRecord>(IntegralTimeRecord.builder().userId(userId).businessId(businessId).build()));
		return false;
	}
	/**
	 * 0为未开启积分
	 */
	@Override
	public Result<?> timeLong(String userId,String dwCode,String businessId){
		//清理该人员的时间记录,并重新记录
		IntegralTimeRecord timeRecord = IntegralTimeRecord.builder().userId(userId).build();
		integralTimeRecordService.delete(new EntityWrapper<IntegralTimeRecord>(timeRecord));
		integralTimeRecordService.insert(timeRecord.setBusinessId(businessId).setTimeLong(System.currentTimeMillis()));
		Open config = getConfig(dwCode);
		Map<String,Object> map = Maps.newHashMap();
		if(config.isOpen){
			map.put("readLong", 0);
			map.put("learnLong", 0);
		}else{
			map.put("readLong", config.getConfig().getReadTime());
			map.put("learnLong", config.getConfig().getLearnTime());
		}
		return Result.ok(map);
	}
	
	/**
	 * //添加历史记录
	 * @param conf
	 * @param userId
	 * @param topDeptId
	 * @param businessId
	 * @param addScore
	 * @param calendar
	 */
	private void saveHistory(InConfig conf,String userId,String dwCode,String businessId,int addScore,Calendar calendar){
		IntegralHistory history = IntegralHistory.builder()
		.userId(userId)
		.dwCode(dwCode)
		.businessId(StringUtils.isNotBlank(businessId)?businessId:"")
		.classify(conf.getId()).classifyName(conf.getName())
		.classifyType(conf.getType()).score(addScore)
		.nian(calendar.get(Calendar.YEAR)).yue(calendar.get(Calendar.MONTH)+1)
		.ri(calendar.get(Calendar.DAY_OF_MONTH)).build();
		integralHistoryService.insert(history); 
		statistics(conf.getType(),userId,addScore);
	}
	
	private void statistics(String conf,String userId,int score){
		try {
			if(conf.equals(integral.integral_formal.getValue()) 
					||conf.equals(integral.integral_one_day.getValue())
					||conf.equals(integral.integral_one_week.getValue())
					||conf.equals(integral.integral_smart.getValue())){
//				ExePoolUtil2.getIns().execute(()->
//						integralExamJfpvService.saveJfpv(userService.selectById(userId),score));
			}
		} catch (Exception e) {
			e.printStackTrace();
			//不需要回滚
		}
	}
	/**
	 * 应增积分
	 * @param histories
	 * @param conf
	 * @param right
	 */
	private int addScore(List<IntegralHistory> histories,InConfig conf, boolean right){
		//该类型的今日总分
		int total = histories.stream().mapToInt(hist -> hist.getScore()).sum();
		if(total >= conf.getMax())
			return 0;
		//应该加多少分
		int addTmp = right ? conf.getLongAndRight() : conf.getMin(); 
		return (total + addTmp) > conf.getMax() ? (conf.getMax() - total) : addTmp; 
	}
	
	/**
	 * 获取今日历史记录
	 * @param calendar
	 * @param userId
	 */
	private List<IntegralHistory> getHistory(Calendar calendar,String userId,integral integral){
		return integralHistoryService.selectList(new EntityWrapper<IntegralHistory>()
				.eq("CLASSIFY", integral.getId())
				.eq("USER_ID",userId)
				.eq("nian", calendar.get(Calendar.YEAR))
				.eq("yue", calendar.get(Calendar.MONTH)+1)
				.eq("ri", calendar.get(Calendar.DAY_OF_MONTH)));
		
	}
	/**
	 * 是否开启
	 * @param topDeptId
	 * @param userId
	 */
	private Open getConfig(String dwCode){
		boolean isOpen = false;
		if(StringUtils.isBlank(dwCode) || dwCode.length() < Const.dwCodeSubLength){
			isOpen = true;
			return new Open().setOpen(isOpen);
		}
		IntegralConfig config = integralConfigService.selectOne(new EntityWrapper<>(IntegralConfig.builder().dwCode(dwCode.substring(0, Const.dwCodeSubLength)).build()));
		
		if(config == null || config.getOpen().intValue() == Const.integralOpen.no.getValue())
			isOpen = true;
		return new Open().setOpen(isOpen).setConfig(config);
	}
	
	/**
	 * 更新主表总积分
	 * @param userId
	 * @param topDeptId
	 * @param addScore
	 */
	private void updateUserScore(String userId,String dwCode,int addScore){
		IntegralUser user = this.selectOne(new EntityWrapper<IntegralUser>().eq("USER_ID",userId));
		if(user == null){
			this.insert(IntegralUser.builder().userId(userId).total(addScore).dwCode(dwCode).build());
		}else{
			this.updateById(user.setTotal(user.getTotal()+addScore));
		}
	}
	
	/**
	 * 获取最大最新值
	 * @param integral
	 * @param config
	 */
	private InConfig getMinMax(integral integral,IntegralConfig config){
		InConfig conf = new InConfig();
		conf.setId(integral.getId()).setName(integral.getName()).setType(integral.getValue());
		switch (integral){
			case integral_formal:
				conf.setMax(config.getFormalMax()).setMin(config.getFormalMin()).setLongAndRight(config.getFormalR());
				break;
			case integral_learn:
				conf.setMax(config.getLearnMax()).setMin(config.getLearnMin()).setLongAndRight(config.getLearnTime());
				break;
			case integral_login:
				conf.setMax(config.getLoginMax()).setMin(config.getLoginMin());
				break;
			case integral_one_day:
				conf.setMax(config.getOneDayMax()).setMin(config.getOneDayMin()).setLongAndRight(config.getOneDayR());
				break;
			case integral_one_week:
				conf.setMax(config.getOneWeekMax()).setMin(config.getOneWeekMin()).setLongAndRight(config.getOneWeekR());
				break;
			case integral_photo:
				conf.setMax(config.getPhotoMax()).setMin(config.getPhotoMin());
				break;
			case integral_read:
				conf.setMax(config.getReadMax()).setMin(config.getReadMin()).setLongAndRight(config.getReadTime());
				break;
			case integral_share:
				conf.setMax(config.getShareMax()).setMin(config.getShareMin());
				break;
			case integral_smart:
				conf.setMax(config.getSmartMax()).setMin(config.getSmartMin()).setLongAndRight(config.getSmartR());
				break;
			default:
				break;
		} 
		return conf;
	}
	
	@Data
	@NoArgsConstructor
	@AllArgsConstructor
	@Accessors(chain = true)
	class InConfig {
		private int min; //最小值
		private int longAndRight; //时长 或 答题正确的积分
		private int max; //最大值
		private String name; //加分项名称
		private String id;	 //积分项id
		private String type; //加分项英文名称
	}
	
	@Data
	@NoArgsConstructor
	@AllArgsConstructor
	@Accessors(chain = true)
	class Open {
		private boolean isOpen; //最小值
		private IntegralConfig config;
	} 
}